﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using InkFx.WinControl.Core;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTGS = InkFx.WinControl.XIDEGroupState;

namespace InkFx.WinControl
{
    /// <summary>
    /// 
    /// </summary>
    [ToolboxItem(false)]
    public partial class XIDEFloatForm : System.Windows.Forms.Form
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        [Obsolete("不建议手动调用 XIDEFloatForm 的构造函数", false)]
        public XIDEFloatForm()
        {
            InitializeComponent();
            base.Padding = new Padding(XIDEPanel.SPLIT_SIZE);
            //base.DoubleBuffered = true; //这种需要快速弹出的窗体, 设置 双缓冲 只会减慢启动速度
            this.ShowInTaskbar = false;
        }


        #region  字 段 属 性

        /// <summary>
        /// 内部字段
        /// </summary>
        protected Color m_BorderColor = SystemColors.Control;


        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public virtual Color BorderColor
        {
            get { return m_BorderColor; }
            set { var color = this.BorderColor; /*if (value.A < 255) { value = Color.FromArgb(255, value.R, value.G, value.B); }*/ if (color.A != value.A || color.R != value.R || color.G != value.G || color.B != value.B) { m_BorderColor = value; this.OnBorderColorChanged(EventArgs.Empty); this.Invalidate(); } }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new System.Windows.Forms.FormBorderStyle FormBorderStyle
        {
            get
            {
                if (base.FormBorderStyle != System.Windows.Forms.FormBorderStyle.None)
                    base.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                return System.Windows.Forms.FormBorderStyle.None;
            }
            set
            {
                base.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false)]
        public new System.Windows.Forms.FormWindowState WindowState
        {
            get { return base.WindowState; }
            set
            {
                base.WindowState = value == FormWindowState.Minimized ? FormWindowState.Normal : value;
                this.Invalidate();
            }
        }






        /// <summary>
        /// 内部字段
        /// </summary>
        protected static readonly object m_EventBorderColorChanged = new object();

        /// <summary>
        /// 边框颜色发生改变时发生
        /// </summary>
        [CategorySkinTheme, Browsable(true), Description("边框颜色发生改变时发生")]
        public event EventHandler BorderColorChanged
        {
            add { base.Events.AddHandler(m_EventBorderColorChanged, value); }
            remove { base.Events.RemoveHandler(m_EventBorderColorChanged, value); }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected virtual void OnBorderColorChanged(EventArgs e)
        {
            EventHandler handler = base.Events[m_EventBorderColorChanged] as EventHandler;
            if (handler != null) handler(this, e);
        }

        #endregion


        #region  重 绘 美 化

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);

            var g = e.Graphics;
            var padding = this.Padding;
            var rect1 = new Rectangle(Point.Empty, this.Size);
            var rect2 = new Rectangle(rect1.X + padding.Left, rect1.Y + padding.Top, rect1.Width - padding.Left - padding.Right, rect1.Height - padding.Top - padding.Bottom);

            g.SetClip(rect2, CombineMode.Exclude);
            GUIHelper.FillBack(g, this.BorderColor, rect1, this.Enabled);
            g.SetClip(rect2, CombineMode.Union);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: PaintEventArgs</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);

            //Console.WriteLine("XIDEFloatForm.OnActivated(EventArgs e)");
            if (m_IDEPanel != null && m_Group != null)
            {
                m_IDEPanel.ActiveGroup = m_Group;
                m_Group.Invalidate();
            }
        }

        #endregion


        #region  消 息 处 理

        /// <summary>
        /// 内部字段
        /// </summary>
        protected bool isPosChanged;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="m">Type: ref System.Windows.Forms.Message</param>
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            //bool isMax = Win32API.IsZoomed(this.Handle) || WindowState == FormWindowState.Maximized;
            switch (m.Msg)
            {
                case Win32Msg.WM_NCHITTEST:
                    #region  WM_NCHITTEST
                    {
                        const int PADDING = XIDEPanel.SPLIT_SIZE;
                        FormBorderOffset offset = new FormBorderOffset(XIDEGroup.CAPTION_HEIGHT + 1, PADDING + 1, PADDING + 1, PADDING + 1, PADDING + 1, PADDING + 1);
                        Point screenPoint = new Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF);
                        Point formPoint = ScreenPointToForm(screenPoint);

                        #region  标题栏拖动窗体

                        if (offset.CaptionAndTopSize > 0)
                        {
                            if (true
                                && (formPoint.X > offset.Border && formPoint.X < this.Width - offset.Border)
                                && (formPoint.Y > offset.Border && formPoint.Y < offset.CaptionAndTopSize))
                            {
                                m.Result = (IntPtr)Win32Msg.HTCAPTION; //标题栏拖动
                                break;
                            }
                        }

                        #endregion

                        #region  边框拖动尺寸

                        if (offset.Border > 0)
                        {
                            if (formPoint.X <= offset.Border)
                                if (formPoint.Y <= offset.Border) { m.Result = (IntPtr)HitTest.HTTOPLEFT; break; }
                                else if (formPoint.Y >= this.Height - offset.Border) { m.Result = (IntPtr)HitTest.HTBOTTOMLEFT; break; }
                                else { m.Result = (IntPtr)HitTest.HTLEFT; break; }
                            else if (formPoint.X >= this.Width - offset.Border)
                                if (formPoint.Y <= offset.Border) { m.Result = (IntPtr)HitTest.HTTOPRIGHT; break; }
                                else if (formPoint.Y >= this.Height - offset.Border) { m.Result = (IntPtr)HitTest.HTBOTTOMRIGHT; break; }
                                else { m.Result = (IntPtr)HitTest.HTRIGHT; break; }
                            else if (formPoint.Y <= offset.Border) { m.Result = (IntPtr)HitTest.HTTOP; break; }
                            else if (formPoint.Y >= this.Height - offset.Border) { m.Result = (IntPtr)HitTest.HTBOTTOM; break; }
                        }

                        #endregion


                        base.WndProc(ref m);
                        m.Result = (IntPtr)HitTest.HTCLIENT; //剩下的全都是 客户区
                        break;
                    }
                    #endregion
                case Win32Msg.WM_NCPAINT:
                    #region  WM_NCPAINT
                    SetFormShadow();
                    base.WndProc(ref m);
                    break;
                    #endregion
                case Win32Msg.WM_WINDOWPOSCHANGED:
                    #region  WM_WINDOWPOSCHANGED
                    isPosChanged = true;
                    base.WndProc(ref m);
                    isPosChanged = false;
                    break;
                    #endregion
                case Win32Msg.WM_NCCALCSIZE:
                    break;
                case Win32Msg.WM_GETMINMAXINFO:
                    #region  WM_GETMINMAXINFO
                    {
                        const int PADDING = XIDEPanel.SPLIT_SIZE;
                        bool isNone = this.FormBorderStyle == System.Windows.Forms.FormBorderStyle.None;
                        Rectangle rectWork = System.Windows.Forms.Screen.GetWorkingArea(this);
                        MINMAXINFO minmax = (MINMAXINFO)m.GetLParam(typeof(MINMAXINFO));

                        FormBorderOffset offset = new FormBorderOffset(XIDEGroup.CAPTION_HEIGHT + 1, PADDING + 1, PADDING + 1, PADDING + 1, PADDING + 1, PADDING + 1);
                        int leftSize = isNone ? 0 : offset.LeftSize;
                        int rightSize = isNone ? 0 : offset.RightSize;
                        int topSize = isNone ? 0 : offset.TopSize;
                        int bottomSize = isNone ? 0 : offset.BottomSize;
                        //int leftSize = offset.LeftSize;
                        //int rightSize = offset.RightSize;
                        //int topSize = offset.TopSize;
                        //int bottomSize = offset.BottomSize;

                        minmax.maxPosition.X = 0 - leftSize;
                        minmax.maxPosition.Y = 0 - topSize;
                        minmax.maxSize.Width = rectWork.Width + leftSize + rightSize;
                        minmax.maxSize.Height = rectWork.Height + topSize + bottomSize;

                        minmax.minTrackSize = MinimumSize != Size.Empty ? MinimumSize : new Size(140, XIDEGroup.CAPTION_HEIGHT * 2 + offset.TopSize + offset.BottomSize + 2);
                        Marshal.StructureToPtr(minmax, m.LParam, true);
                        m.Result = Win32API.IntPtrFlase;

                        break;
                    }
                    #endregion
                case Win32Msg.WM_NCACTIVATE:
                    #region  WM_NCACTIVATE
                    DrawNonClient(m.WParam.ToInt32() > 0);
                    //base.WndProc(ref m);
                    m.Result = Win32API.IntPtrTrue;
                    break;
                    #endregion
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        /// <summary>
        /// 设置窗体边框阴影 (仅支持 Win7+ 系统, 且 窗体不能是圆角, 本函数才会生效)
        /// </summary>
        protected virtual void SetFormShadow()
        {
            if (!Form.IsDesignMode && Win32API.EnableAero)
            {
                int v = 2;
                Win32API.DwmSetWindowAttribute(this.Handle, 2, ref v, 4);
                Win32API.MARGINS margins = new Win32API.MARGINS { bottomHeight = 1, leftWidth = 1, rightWidth = 1, topHeight = 1 };
                Win32API.DwmExtendFrameIntoClientArea(this.Handle, ref margins);
            }
        }
        /// <summary>
        /// 鼠标的屏幕坐标 转换成 窗体坐标 (包括 客户区 和 非客户区)
        /// </summary>
        /// <param name="screenPoint">Type: Point</param>
        /// <returns></returns>
        public Point ScreenPointToForm(Point screenPoint)
        {
            Point location = this.Location;
            return new Point(screenPoint.X - location.X, screenPoint.Y - location.Y);
        }

        /// <summary>
        /// 执行非客户区重绘
        /// </summary>
        /// <param name="active">Type: bool</param>
        public void DrawNonClient(bool active)
        {
        }


        #endregion






        #region  IDEPanel 相 关

        /// <summary>
        /// 
        /// </summary>
        /// <param name="idePanel">Type: XIDEPanel</param>
        /// <param name="group">Type: XIDEGroup</param>
        /// <param name="panel">Type: XIDESplitPanel</param>
        /// <param name="rect">Type: Rectangle</param>
        /// <returns></returns>
        public static XIDEFloatForm FloatGroup(XIDEPanel idePanel, XIDEGroup group, XIDESplitPanel panel, Rectangle rect)
        {
            if (panel == null) throw new InvalidOperationException("浮动 XIDEGroup 之前, 必须先指定 其归属的 XIDESplitPanel");
            XIDEPopPanel.DisposeActive();

            XIDEFloatForm form = new XIDEFloatForm();
            idePanel.TransLayout(() =>
            {
                var theme = idePanel.Theme;
                form.m_IDEPanel = idePanel;
                form.m_SplitPanel = panel;
                form.m_Group = group;
                form.Font = idePanel.Font;
                if (theme != null)
                {
                    form.BackColor = theme.XIDEFloatForm_BackColor;
                    form.BorderColor = theme.XIDEFloatForm_BorderColor;
                }

                if (rect != Rectangle.Empty) { form.StartPosition = FormStartPosition.Manual; form.Bounds = rect; }

                group.Dock = DockStyle.Fill;
                group.BaseParent = form;
                group.Visible = true;
                group.m_State = DTGS.Float;
                form.Show(idePanel.FindForm());
                group.Focus();

                idePanel.Invalidate();
            });

            return form;
        }


        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEPanel m_IDEPanel = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDEGroup m_Group = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected XIDESplitPanel m_SplitPanel = null;
        /// <summary>
        /// 内部字段
        /// </summary>
        protected List<XIDETipForm> m_ListTipForm = new List<XIDETipForm>();


        /// <summary>
        /// 
        /// </summary>
        public XIDEPanel IDEPanel
        {
            get { return m_IDEPanel; }
        }
        /// <summary>
        /// 
        /// </summary>
        public XIDEGroup Group
        {
            get { return m_Group; }
        }
        /// <summary>
        /// 
        /// </summary>
        public XIDESplitPanel SplitPanel
        {
            get { return m_SplitPanel; }
        }

        public static readonly object CENTER_TIPTAG = new object();
        /// <summary>
        /// 
        /// </summary>
        public void ShowTipForm()
        {
            var idePanel = IDEPanel;
            if (idePanel == null || idePanel.Disposing || idePanel.IsDisposed) return;

            var list1 = new List<object>();
            var list2 = new List<object>();
            list1.Add(idePanel);
            var groupC = idePanel.FindCenterGroup();
            if (groupC == null || groupC == this.Group) list1.Add(CENTER_TIPTAG);

            var list9 = idePanel.GetListGroup();
            if (list9 != null)
            {
                var curr = this.Group;
                var list4 = new List<XIDEGroup>(list9);
                foreach (var group in list4) { if (!(group == curr || !ShowIDETipForm(group))) { list1.Add(group); } }
            }

            var point = System.Windows.Forms.Control.MousePosition;
            foreach (var tag in list1)
            {
                if (tag is System.Windows.Forms.Control)
                {
                    var rect = Win32API.GetWindowRectangle(((System.Windows.Forms.Control)tag).Handle);
                    if (rect.Contains(point)) { list2.Add((System.Windows.Forms.Control)tag); }
                }
                else if (tag == CENTER_TIPTAG)
                {
                    var rect = idePanel.FindCenterRectWindow();
                    if (rect.Contains(point)) { list2.Add(CENTER_TIPTAG); }
                }
            }

            var list3 = new List<XIDETipForm>(m_ListTipForm);
            foreach (var ctrl in list2)
            {
                var temp = ctrl;
                XIDETipForm form = m_ListTipForm.Find(x => x.TipTag == temp);
                if (form != null) { list3.Remove(form); form.Invalidate(); }
                else
                {
                    form = XIDETipForm.ShowTipForm(idePanel, ctrl, this);
                    if (form != null) m_ListTipForm.Add(form);
                }
            }

            foreach (var form in list3)
            {
                form.Dispose();
                m_ListTipForm.Remove(form);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public void HideTipForm()
        {
            if (m_ListTipForm != null)
            {
                foreach (var form2 in m_ListTipForm) { form2.Dispose(); }
                m_ListTipForm.Clear();
            }
        }




        private bool ShowIDETipForm(XIDEGroup group)
        {
            if (group == null) return false;
            bool hide = !group.Visible || (group == this.Group) || (group.State != DTGS.Expand && group.State != DTGS.Float && group.State != DTGS.Popup);
            if (hide) return false;

            //var handle = this.Handle;
            //var rect = Win32API.GetWindowRectangle(handle);
            //if (handle != Win32API.WindowFromPoint(new Point(rect.X + 1, rect.Y + 1))) return false;
            //if (handle != Win32API.WindowFromPoint(new Point(rect.X + rect.Width - 1, rect.Y + 1))) return false;
            //if (handle != Win32API.WindowFromPoint(new Point(rect.X + 1, rect.Y + rect.Height - 1))) return false;
            //if (handle != Win32API.WindowFromPoint(new Point(rect.X + rect.Width - 1, rect.Y + rect.Height - 1))) return false;
            
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public XIDETipEventArgs NewTipEventArgs()
        {
            if (m_ListTipForm == null || m_ListTipForm.Count <= 0) return null;

            foreach (var form in m_ListTipForm)
            {
                var e = form.NewTipEventArgs();
                if (e != null) { return e; }
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            base.DoubleBuffered = true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: EventArgs</param>
        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);

            if (MouseButtons == MouseButtons.Left) this.ShowTipForm();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e">Type: ControlEventArgs</param>
        protected override void OnControlRemoved(ControlEventArgs e)
        {
            base.OnControlRemoved(e);

            XIDEGroup group = null;
            foreach (var ctrl in this.Controls) { if (ctrl is XIDEGroup) { group = (XIDEGroup)ctrl; break; } }

            if (group != null) { this.m_Group = group; }
            else { this.Dispose(); }
        }

        #endregion


        /// <summary>
        /// 释放 XIDEFloatForm 并且让 关联的 XIDEGroup 归位
        /// </summary>
        public virtual new void Dispose()
        {
            HideTipForm();
            var group = this.Group;
            var form = group == null ? null : group.FindForm();
            if (form == this) { group.BaseParent = null; }

            m_Group = null;
            m_SplitPanel = null;
            m_IDEPanel = null;
            if (!this.Disposing && !this.IsDisposed) { this.Close(); base.Dispose(); }
        }
    }


}
